package com.panda.admin.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * author: tcy
 * createDate: 2023/6/27
 * description: 雪花算法重写，生成16位id
 */
public class SnowflakeIdGenerator {
    private static final Logger log = LoggerFactory.getLogger(SnowflakeIdGenerator.class);
    private static final Pattern PATTERN_LONG_ID = Pattern.compile("^([0-9]{15})([0-9a-f]{32})([0-9a-f]{3})$");
    private static final Pattern PATTERN_HOSTNAME = Pattern.compile("^.*\\D+([0-9]+)$");
    private static final long OFFSET = LocalDate.of(2000, 1, 1).atStartOfDay(ZoneId.of("Z")).toEpochSecond();
    private static final long MAX_NEXT = 65535L;
    private static final long SHARD_ID = getServerIdAsLong();
    private static long offset = 0L;
    private static long lastEpoch = 0L;

    public SnowflakeIdGenerator() {
    }

    public static long nextId() {
        return nextId(System.currentTimeMillis() / 1000L);
    }

    private static synchronized long nextId(long epochSecond) {
        if (epochSecond < lastEpoch) {
            log.info("时间被回调，当前：{}，上一次：{}", epochSecond, lastEpoch);
            epochSecond = lastEpoch;
        }

        if (lastEpoch != epochSecond) {
            lastEpoch = epochSecond;
            reset();
        }

        ++offset;
        long next = offset & 65535L;
        if (next == 0L) {
            log.info("1s内达到最大ID，时间为：{}", epochSecond);
            return nextId(epochSecond + 1L);
        } else {
            return generateId(epochSecond, next, SHARD_ID);
        }
    }

    private static void reset() {
        offset = 0L;
    }

    private static long generateId(long epochSecond, long next, long shardId) {
        return epochSecond - OFFSET << 21 | next << 5 | shardId;
    }

    private static long getServerIdAsLong() {
        String serverId = System.getenv("SERVER_ID");
        if (serverId != null) {
            try {
                long id = Long.parseLong(serverId);
                if (id >= 0L && id < 32L) {
                    log.info("从环境变量检测服务器ID为{}", id);
                    return id;
                }

                log.info("SERVER_ID范围为[0, 31]");
            } catch (NumberFormatException var6) {
                log.error("SERVER_ID只能为数字");
            }
        }

        try {
            String hostname = InetAddress.getLocalHost().getHostName();
            Matcher matcher = PATTERN_HOSTNAME.matcher(hostname);
            if (matcher.matches()) {
                long n = Long.parseLong(matcher.group(1));
                if (n >= 0L && n < 8L) {
                    log.info("从主机名检测服务器ID为{}", n);
                    return n;
                }
            }
        } catch (UnknownHostException var5) {
            log.error("无法获取主机名，设置服务器ID为0");
        }

        return 0L;
    }
}
